﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AutoMapper;

namespace MyAutoMapper
{
    /// <summary>
    /// AutoMapper:
    /// 是一个简单的对象映射框架(OOM)，
    /// 对象映射的原理是把一种类型的输入对象转为为不同类型的输出对象
    /// 通俗讲就是通过一些约束将一种类型中的数据自动映射到另一种数据类型中
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            var _pro = new Program();
            //_pro.Fun1();
            //_pro.Fun2();
            //_pro.Fun3();
            //_pro.Fun4();
            _pro.Fun7();

            Console.ReadLine();
        }

        public void Fun1()
        {
            //初始化AutoMapper
            Mapper.Initialize(y => { });
            //源对象
            var source = new Source
            {
                Id = 1,
                Name = "张三"
            };
            //映射
            var target = Mapper.Map<Source, Target>(source);
            Console.WriteLine("简单映射");
            Console.WriteLine(target.Id);
            Console.WriteLine(target.Name);
            Console.WriteLine(target.Age);

            Console.WriteLine("/end---------------------");
        }

        //映射 CreateMap
        public void Fun2()
        {
            //AutoMapper 初始化操作
            //此操作在一个应用程序中只能执行一次
            //在初始化方法中科院初始化映射中的任何操作
            Mapper.Initialize(config =>
            {
                config.CreateMap<Source1, Target1>();
            });
            //如果不配置CreateMap ，在目标类型有未映射的属性就会报错 

            var source = new Source1 { Id = 1, SName = "李四", Age = 22, DateTime = "2018-7-7" };
            Console.WriteLine("配置CreateMap。如果不配置，目标类型有未映射的属性就会报错");
            var target = Mapper.Map<Source1, Target1>(source);
            Console.WriteLine(target.Id);
            Console.WriteLine(target.TName);
            Console.WriteLine(target.Age);
            Console.WriteLine(target.DateTime);
            Console.WriteLine("/end---------------------");
        }

        //反向映射
        public void Fun3()
        {
            //反向映射 ReverseMap
            Mapper.Initialize(config =>
            {
                //config.CreateMap<Source1, Target1>();
                config.CreateMap<Source1, Target1>().ReverseMap();
            });

            var source = new Source1 { Id = 2, SName = "张三", Age = 19, DateTime = "2018-7-8" };

            var target = Mapper.Map<Source1, Target1>(source);
            Console.WriteLine(target.Id);
            Console.WriteLine(target.TName);
            Console.WriteLine(target.Age);
            Console.WriteLine(target.DateTime);

            //反向映射
            try
            {
                var reverseSource = Mapper.Map<Target1, Source1>(target);
                Console.WriteLine(reverseSource.Id);
                Console.WriteLine(reverseSource.SName);
                Console.WriteLine(reverseSource.Age);
                Console.WriteLine(reverseSource.DateTime);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.InnerException);
            }

        }

        //属性名称不一致时的映射

        public void Fun4()
        {
            Mapper.Initialize(config =>
            {
                config.CreateMap<Source1, Target1>()

                    .ForMember(t => t.TName, o => o.MapFrom(s => s.SName)).ReverseMap();

            });

            var source = new Source1 { Id = 2, SName = "张三", Age = 19, DateTime = "2018-7-8" };

            var target = Mapper.Map<Source1, Target1>(source);
            Console.WriteLine(target.Id);
            Console.WriteLine(target.TName);
            Console.WriteLine(target.Age);
            Console.WriteLine(target.DateTime);

            //反向映射

            var reverseSource = Mapper.Map<Target1, Source1>(target);
            Console.WriteLine(reverseSource.Id);
            Console.WriteLine(reverseSource.SName);
            Console.WriteLine(reverseSource.Age);
            Console.WriteLine(reverseSource.DateTime);

        }

        //空值替换
        //映射前后的操作
        //条件映射
        public void Fun5()
        {
            Mapper.Initialize(c =>
            {
                c.CreateMap<Source1, Target1>()
                //映射前的操作
                 .BeforeMap((s, t) =>
                 {
                     s.Age += 10;
                 })
                    //映射后的操作
                    .AfterMap((s, t) =>
                    {
                        t.Age += 10;
                    })
                    //年龄不大于10 不映射年龄这个属性的值，那值就是默认的0，但是映射后+10，所以就是10
                    .ForMember(t=>t.Age,o=>o.Condition(s=>s.Age>30))
                .ForMember(t => t.TName, o => o.MapFrom(s => s.SName))
                .ForMember(t => t.TName, o => o.NullSubstitute("是空"));
            });

            var _s = new Source1 { Id = 9, Age = 90, DateTime = "2018-7-8" };
            var _t = Mapper.Map<Source1, Target1>(_s);
            Console.WriteLine(_t.Id);
            Console.WriteLine(_t.TName);
            Console.WriteLine(_t.Age);
            Console.WriteLine(_t.DateTime);
            Console.WriteLine("--------------------");

            var _ss = new Source1 { Id = 9, Age = 9, DateTime = "2018-7-8" };
            var _tt = Mapper.Map<Source1, Target1>(_ss);
            Console.WriteLine(_tt.Id);
            Console.WriteLine(_tt.TName);
            Console.WriteLine(_tt.Age);
            Console.WriteLine(_tt.DateTime);
        }

        //泛型映射   ？不解？
        //public void Fun6()
        //{
        //    Mapper.Initialize(c =>
        //    {
        //        c.CreateMap(typeof(Source1<>), typeof(Target1<>))
        //            .ForMember("TName", y => y.MapFrom("SName"))
        //            .ForMember("TName", o => o.NullSubstitute("空的"));
        //    });

        //    var s = new Source1<String> { Id=1,Age="x",SName=""}
        //}


        //使用帮助类
        public void Fun7()
        {
            List<Source1> ss = new List<Source1>();

            var _s = new Source1 { Id = 9, Age = 90, DateTime = "2018-7-8" };
            ss.Add(_s);
            var _t = MyAutoMapper.Extensions.MapTo<Target1>(_s);
            Console.WriteLine(_t.Id);
            Console.WriteLine(_t.TName);
            Console.WriteLine(_t.Age);
            Console.WriteLine(_t.DateTime);
            Console.WriteLine("--------------------");

            var t = new Target1 { Id=99,Age=19 };
            var _tt = Extensions.MapTo<Source1, Target1>(_s,t);
            Console.WriteLine(_tt.Id);
            Console.WriteLine(_tt.TName);
            Console.WriteLine(_tt.Age);
            Console.WriteLine(_tt.DateTime);
            Console.WriteLine("--------------------");

            var _s1 = new Source1 { Id = 19, Age = 190, DateTime = "2018-7-8" };
            ss.Add(_s1);
            Console.WriteLine("xxxxxxxxxxxxxxxxxxxxxx");
            var _temp = Extensions.MapToList<Target1>(ss);

            foreach (var item in _temp)
            {
                Console.WriteLine(item.Id);
                Console.WriteLine(item.TName);
                Console.WriteLine(item.Age);
                Console.WriteLine(item.DateTime);
                Console.WriteLine("--------------------");
            }
        }
    }

    #region fun1
    class Source
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }

    }

    class Target
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }

    }
    #endregion

    #region fun2
    class Source1
    {
        public int Id { get; set; }
        public string SName { get; set; }
        public string DateTime { get; set; }
        public int Age { get; set; }
    }

    class Target1
    {
        public int Id { get; set; }
        public string TName { get; set; }
        public DateTime DateTime { get; set; }
        public int Age { get; set; }
    }
    #endregion
}
